﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

using DanielVaughan.Calcium.Services;

namespace DanielVaughan.Calcium.Gui
{
	public partial class ShellView : ICommandService
	{
		#region External Command Binding support
		/// <summary>
		/// <see cref="ICommandService.AddCommandBindingForContentType{TContent}"/>
		/// </summary>
		public void AddCommandBindingForContentType<TContent>(ICommand command,
			Func<TContent, bool> executeHandler, Func<TContent, bool> canExecuteHandler)
			where TContent : class
		{
			/* When the workspace view changes, 
			 * if the view is viewType then the specified command will be enabled depending 
			 * on the result of the command.CanExecute. 
			 * When the command is executed the current view's specified member will be called. */
			CommandBindings.Add(new CommandBinding(command,
				(sender, e) =>
				{
					var content = GetSelectedContent<TContent>();
					if (content == null)
					{
						/* Shouldn't get here because the CanExecute handler should prevent it. */
						return;
					}
					e.Handled = executeHandler(content);
				},
				(sender, e) =>
				{
					var content = GetSelectedContent<TContent>();
					if (content == null)
					{
						e.CanExecute = false;
						return;
					}
					e.CanExecute = canExecuteHandler(content);
				}));
		}

		/// <summary>
		/// <see cref="ICommandService.AddCommandBindingForContentType{TContent}"/>
		/// </summary>
		public void AddCommandBindingForContentType<TContent>(
			ICommand command,
			Func<TContent, object, bool> executeHandler,
			Func<TContent, object, bool> canExecuteHandler)
			where TContent : class
		{
			/* When the workspace view changes, 
			 * if the view is viewType then the specified command 
			 * will be enabled depending on the result of the command.CanExecute. 
			 * When the command is executed the current view's specified member 
			 * will be called. */
			CommandBindings.Add(new CommandBinding(command,
				(sender, e) =>
				{
					var content = GetSelectedContent<TContent>();
					if (content == null)
					{
						/* Shouldn't get here because the CanExecute handler 
						 * should prevent it. */
						return;
					}
					e.Handled = executeHandler(content, e.Parameter);
				},
				(sender, e) =>
				{
					var content = GetSelectedContent<TContent>();
					if (content == null)
					{
						e.CanExecute = false;
						return;
					}
					e.CanExecute = canExecuteHandler(content, e.Parameter);
				}));
		}

		/// <summary>
		/// <see cref="ICommandService.AddCommandBindingForContentType{TContent}"/>
		/// </summary>
		public void AddCommandBindingForContentType<TContent>(ICommand command,
			Func<TContent, bool> executeHandler,
			Func<TContent, bool> canExecuteHandler, KeyGesture keyGesture) where TContent : class
		{
			AddCommandBindingForContentType(command, executeHandler, canExecuteHandler);
			var keybinding = new KeyBinding(command, keyGesture);
			InputBindings.Add(keybinding);
		}

		public void AddCommandBinding(ICommand command,
			Func<bool> executeHandler, Func<bool> canExecuteHandler)
		{
			CommandBindings.Add(new CommandBinding(command,
				(sender, e) =>
				{
					e.Handled = executeHandler();
				},
				(sender, e) =>
				{
					e.CanExecute = canExecuteHandler();
				}));
		}

		public void AddCommandBinding(ICommand command,
			Func<bool> executeHandler, Func<bool> canExecuteHandler, KeyGesture keyGesture)
		{
			AddCommandBinding(command, executeHandler, canExecuteHandler);

			var keybinding = new KeyBinding(command, keyGesture);
			InputBindings.Add(keybinding);
		}

		public void RemoveCommandBinding(ICommand command)
		{
			ArgumentValidator.AssertNotNull(command, "command");

			var commandBinding = (from binding in CommandBindings.OfType<CommandBinding>()
								  where binding.Command == command
								  select binding).FirstOrDefault();

			if (commandBinding != null)
			{
				CommandBindings.Remove(commandBinding);
			}
		}

		public void RegisterKeyGester(KeyGesture keyGesture, ICommand command)
		{
			var keybinding = new KeyBinding(command, keyGesture);
			InputBindings.Add(keybinding);
		}
		#endregion
	}
}
